<template>
  <div class="el-quarter-picker">
    <el-popover
      v-model:visible="visible"
      :disabled="!canPopover"
      :tabindex="null"
      placement="bottom-start"
      transition="el-zoom-in-top"
      trigger="click"
      :teleported="true"
      :popper-class="'quarter-picker-popup'"
      :width="300"
    >
      <div class="el-date-picker">
        <div class="el-picker-panel__body">
          <div
            class="el-date-picker__header el-date-picker__header--bordered"
            style="margin: 0px; line-height: 30px"
          >
            <button
              type="button"
              @click="clickLast"
              aria-label="前一年"
              class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left"
            ></button>
            <span role="button" class="el-date-picker__header-label" @click="clickYear">{{
              title
            }}</span>
            <button
              type="button"
              @click="clickNext"
              aria-label="后一年"
              class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right"
            ></button>
          </div>
          <div class="el-picker-panel__content" style="margin: 0px; width: 100%">
            <table class="el-month-table" v-if="viewType === 1">
              <tbody>
                <tr>
                  <td :class="{ today: viewList[0]?.current, current: viewList[0]?.active }">
                    <div>
                      <a class="cell" @click="clickItem(viewList[0])">上半年</a>
                    </div>
                  </td>
                </tr>
                <tr>
                  <td :class="{ today: viewList[1]?.current, current: viewList[1]?.active }">
                    <div>
                      <a class="cell" @click="clickItem(viewList[1])">下半年</a>
                    </div>
                  </td>
                </tr>
              </tbody>
            </table>

            <table class="el-year-table" v-else>
              <tbody>
                <tr v-for="line in lineCount" :key="line">
                  <td
                    v-for="index in line * 4 <= viewList.length
                      ? 4
                      : viewList.length - (line - 1) * 4"
                    :key="index"
                    :class="{
                      today: viewList[(line - 1) * 4 + index - 1]?.current,
                      current: viewList[(line - 1) * 4 + index - 1]?.active,
                    }"
                  >
                    <div>
                      <a class="cell" @click="clickItem(viewList[(line - 1) * 4 + index - 1])">
                        {{ viewList[(line - 1) * 4 + index - 1]?.label }}
                      </a>
                    </div>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
      </div>

      <template #reference>
        <el-input
          v-model="text"
          @change="changeText"
          @mouseenter="mouseEnter"
          @mouseleave="mouseLeave"
          :placeholder="placeholder"
          :size="size"
          :readonly="!canEdit"
          :disabled="disabled"
        >
          <template #prefix>
            <i class="el-input__icon el-icon-date" />
          </template>
          <template #suffix>
            <i
              class="el-input__icon el-icon-circle-close"
              v-show="showClear"
              style="cursor: pointer"
              @click.stop="clear"
            />
          </template>
        </el-input>
      </template>
    </el-popover>
  </div>
</template>

<script setup>
import 'element-plus/dist/index.css'
import { ref, watch, onMounted, onBeforeUnmount, computed } from 'vue'
import dayjs from 'dayjs'
import { useVModel } from '@vueuse/core'

const props = defineProps({
  placeholder: { type: String, default: '' },
  size: { type: String, default: '' },
  readonly: { type: Boolean, default: false },
  clearable: { type: Boolean, default: true },
  editable: { type: Boolean, default: true },
  disabled: { type: Boolean, default: false },
  format: { type: String, default: 'yyyy年H' }, // 修改为 H 表示上/下半年
  valueFormat: { type: String, default: 'yyyy-h' }, // 修改为 h 表示 1/2
  modelValue: { type: String, default: '' },
})

const emit = defineEmits(['update:modelValue'])
const value = useVModel(props, 'modelValue', emit)

const visible = ref(false)
const showClear = ref(false)
const canEdit = ref(!props.readonly && props.editable)
const canPopover = ref(!props.disabled && !props.readonly)
const text = ref('')
const viewType = ref(1)
const viewYear = ref(new Date().getFullYear())
const viewList = ref([])
const lineCount = ref(0)
const title = ref('')
const data = ref([0, 0])

watch(
  () => props.modelValue,
  (val) => changeValue(val),
)
watch(
  () => props.readonly,
  (val) => (canEdit.value = !val && props.editable),
)
watch(
  () => props.editable,
  (val) => (canEdit.value = !props.readonly && val),
)
watch(
  () => props.disabled,
  (val) => (canPopover.value = !val && !props.readonly),
)

function changeValue(val) {
  viewType.value = 1
  if (val) {
    formatFrom(val, props.valueFormat)
    text.value = formatTo(data.value, props.format)
    viewYear.value = data.value[0]
  } else {
    text.value = ''
    data.value = [0, 0]
    viewYear.value = new Date().getFullYear()
  }
  initView()
}

function changeText() {
  if (checkFormat(props.format, text.value)) {
    formatFrom(text.value, props.format)
    emit('update:modelValue', formatTo(data.value, props.valueFormat))
  } else {
    text.value = data.value[0] && data.value[1] ? formatTo(data.value, props.format) : ''
  }
  visible.value = false
}

function mouseEnter() {
  if (!props.disabled && !props.readonly && props.clearable && text.value) {
    showClear.value = true
  }
}
function mouseLeave() {
  if (!props.disabled && props.clearable) {
    showClear.value = false
  }
}
function clear() {
  showClear.value = false
  visible.value = false
  emit('update:modelValue', '')
}

function initView() {
  const curDate = new Date()
  const curYear = curDate.getFullYear()
  const curHalf = Math.floor(curDate.getMonth() / 6) + 1
  const list = []

  if (viewType.value === 1) {
    list.push({
      label: '上半年',
      year: viewYear.value,
      quarter: 1,
      current: viewYear.value === curYear && curHalf === 1,
      active: viewYear.value === data.value[0] && data.value[1] === 1,
    })
    list.push({
      label: '下半年',
      year: viewYear.value,
      quarter: 2,
      current: viewYear.value === curYear && curHalf === 2,
      active: viewYear.value === data.value[0] && data.value[1] === 2,
    })
    title.value = `${viewYear.value} 年`
  } else {
    console.log(555)
    const start = Math.floor(viewYear.value / 10) * 10
    for (let i = 0; i < 10; i++) {
      const year = start + i
      list.push({
        label: `${year}`,
        year,
        current: year === curYear,
        active: year === data.value[0],
      })
    }
    title.value = `${start} 年 - ${start + 9} 年`
  }
  viewList.value = list
  lineCount.value = Math.ceil(list.length / 4)
}

function clickItem(item) {
  if (viewType.value === 1) {
    emit('update:modelValue', formatTo([item.year, item.quarter], props.valueFormat))
    visible.value = false
  } else {
    viewType.value = 1
    viewYear.value = item.year
    initView()
  }
}
function clickYear() {
  if (viewType.value === 1) {
    viewType.value = 2
    initView()
  }
}
function clickLast() {
  viewYear.value = viewType.value === 1 ? viewYear.value - 1 : viewYear.value - 10
  initView()
}
function clickNext() {
  viewYear.value = viewType.value === 1 ? viewYear.value + 1 : viewYear.value + 10
  initView()
}

function checkFormat(pattern, val) {
  let text = pattern.replace(/[\\^$.+?*\[\]{}!]/g, '\\$&')
  text = text.replace('yyyy', '\\d{4}').replace('H', '[上下]半年').replace('h', '[12]')
  return new RegExp(`^${text}$`).test(val)
}

function formatTo([year, half], pattern) {
  return pattern
    .replace('yyyy', year)
    .replace('H', half === 1 ? '上半年' : '下半年')
    .replace('h', half)
}

function formatFrom(str, pattern) {
  const year = findText(str, pattern, 'yyyy')
  let half = findText(str, pattern, 'h')
  if (half === -1) {
    half = str.includes('上半年') ? 1 : 2
  }
  data.value = [year, half]
}

function findText(str, pattern, find) {
  if (Array.isArray(find)) {
    for (const f of find) {
      const val = findText(str, pattern, f)
      if (val !== -1) return val
    }
    return -1
  }
  const index = pattern.indexOf(find)
  if (index === -1) return -1
  console.log(str)
  if (!str) return
  const val = str.substr(index, index + find.length)
  return find === 'Q' ? '一二三四'.indexOf(val) + 1 : parseInt(val)
}

onMounted(() => {
  changeValue(props.modelValue)

  document.addEventListener('keydown', onKeyDown)
})

onBeforeUnmount(() => {
  document.removeEventListener('keydown', onKeyDown)
})

function onKeyDown(event) {
  if (!visible.value) return
  const [y, h] = data.value[0]
    ? data.value
    : [new Date().getFullYear(), Math.floor(new Date().getMonth() / 6) + 1]
  let newYear = y
  let newHalf = h

  if (event.code === 'ArrowLeft' || event.code === 'ArrowRight') {
    newHalf = h === 1 ? 2 : 1
    newYear =
      event.code === 'ArrowLeft' && h === 1
        ? y - 1
        : event.code === 'ArrowRight' && h === 2
          ? y + 1
          : y
  } else if (event.code === 'ArrowUp') {
    newYear = y - 1
  } else if (event.code === 'ArrowDown') {
    newYear = y + 1
  } else {
    return
  }

  if (newYear < 1000 || newYear > 9999) return
  data.value = [newYear, newHalf]
  viewType.value = 1
  viewYear.value = newYear
  emit('update:modelValue', formatTo(data.value, props.valueFormat))
}
</script>

<style lang="scss">
.el-popper.quarter-picker-popup {
  width: 300px !important;
  padding: 0;

  .el-picker-panel {
    width: 100% !important;
  }

  .el-date-picker {
    width: 100% !important;
    min-width: 300px !important;

    .el-picker-panel__body {
      width: 100% !important;
      min-width: 300px !important;
    }

    .el-picker-panel__content {
      width: 100% !important;
      margin: 0;
      padding: 10px;
    }
  }

  .el-month-table {
    width: 100% !important;
    border-collapse: collapse;

    td {
      width: 100%;
      padding: 12px 0;

      .cell {
        width: 100%;
        padding: 8px;
        text-align: center;
      }
    }
  }
}

.el-quarter-picker {
  width: 220px;
  display: inline-block;
}

.el-year-table {
  width: 100%;
  border-collapse: collapse;

  td {
    padding: 12px 0;
    text-align: center;

    &.current:not(.disabled) .cell {
      color: var(--el-color-primary);
      font-weight: bold;
    }

    .cell {
      width: 100%;
      padding: 8px;
      cursor: pointer;

      &:hover {
        color: var(--el-color-primary);
      }
    }
  }
}
</style>
